﻿using System;
using Ioc.Bll;
using Ioc.Dal;

namespace Ioc.Test
{
    /// <summary>
    /// IOC相关术语
    /// 依赖倒置原则（DIP）：一种软件架构设计的原则（抽象概念）。
    /// 控制反转（IoC）：一种反转流、依赖和接口的方式（DIP的具体实现方式）。
    /// 依赖注入（DI）：IoC的一种实现方式，用来反转依赖（IoC的具体实现方式）。
    /// IoC容器：依赖注入的框架，用来映射依赖，管理对象创建和生存周期（DI框架）。
    ///
    /// ================================================================
    /// 依赖倒置原则（DIP）
    /// ================================================================
    /// DIP简述：
    /// 高层模块不应依赖于低层模块，两者应该依赖于抽象。
    /// 抽象不不应该依赖于实现，实现应该依赖于抽象。
    ///
    /// DIP案例说明：
    /// 场景一  依赖无倒置（低层模块定义接口，高层模块负责实现）
    /// 从上图中，我们发现高层模块的类依赖于低层模块的接口。因此，低层模块需要考虑到所有的接口。如果有新的低层模块类出现时，高层模块需要修改代码，来实现新的低层模块的接口。这样，就破坏了开放封闭原则。
    ///
    /// 场景二 依赖倒置（高层模块定义接口，低层模块负责实现）
    /// 在这个图中，我们发现高层模块定义了接口，将不再直接依赖于低层模块，低层模块负责实现高层模块定义的接口。这样，当有新的低层模块实现时，不需要修改高层模块的代码。
    /// 
    /// DIP优点：
    /// 系统更柔韧：可以修改一部分代码而不影响其他模块。
    /// 系统更健壮：可以修改一部分代码而不会让系统崩溃。
    /// 系统更高效：组件松耦合，且可复用，提高开发效率。
    /// ----------------------------------------------------------------
    ///
    /// ================================================================
    /// 控制反转（IoC）
    /// ================================================================
    /// IoC简述：
    /// DIP是一种 软件设计原则，它仅仅告诉你两个模块之间应该如何依赖，但是它并没有告诉如何做。
    /// IoC则是一种 软件设计模式，它告诉你应该如何做，来解除相互依赖模块的耦合。
    /// 控制反转（IoC），它为相互依赖的组件提供抽象，将依赖（低层模块）对象的获得交给第三方（系统）来控制，即依赖对象不在被依赖模块的类中直接通过new来获取。
    ///
    /// 软件设计原则：原则为我们提供指南，它告诉我们什么是对的，什么是错的。它不会告诉我们如何解决问题。它仅仅给出一些准则，以便我们可以设计好的软件，避免不良的设计。一些常见的原则，比如DRY、OCP、DIP等。
    /// 软件设计模式：模式是在软件开发过程中总结得出的一些可重用的解决方案，它能解决一些实际的问题。一些常见的模式，比如工厂模式、单例模式等等。
    /// 
    /// 高低依赖底层导致组件之间高度耦合，可扩展性较差，它违背了DIP原则。
    /// 高层模块Order类不应该依赖于低层模块SqlServerDal，AccessDal，两者应该依赖于抽象。
    /// 那么我们是否可以通过IoC来优化代码呢？答案是肯定的。
    /// IoC有2种常见的实现方式：依赖注入和服务定位。其中，依赖注入使用最为广泛。
    /// 下面我们将深入理解依赖注入（DI），并学会使用。
    /// ----------------------------------------------------------------
    ///
    /// ================================================================
    /// 依赖注入（DI）
    /// ================================================================
    /// 控制反转（IoC）一种重要的方式，就是将依赖对象的创建和绑定转移到被依赖对象类的外部来实现。
    /// 在上述的实例中，Order类所依赖的对象SqlServerDal的创建和绑定是在Order类内部进行的。
    /// 事实证明，这种方法并不可取。
    /// 既然，不能在Order类内部直接绑定依赖关系，那么如何将SqlServerDal对象的引用传递给Order类使用呢？
    /// 
    /// 依赖注入（DI）：
    /// 它提供一种机制，将需要依赖（低层模块）对象的引用传递给被依赖（高层模块）对象。
    /// 
    /// 方法一 构造函数注入
    /// 方法二 属性注入
    /// 方法三 接口注入
    /// ----------------------------------------------------------------
    ///
    /// ================================================================
    /// IoC容器
    /// ================================================================
    ///
    ///
    /// ----------------------------------------------------------------
    /// </summary>
    public class Program
    {
        public static void Main(string[] args)
        {
            MySqlDal dal = new MySqlDal();

            // 方法一 构造函数注入
            OrderService os = new OrderService(dal); 
            // 方法二 属性注入
            os.Ida = dal; 

            // 方法三 接口注入
            os.SetDependence(dal);

            os.Add();

            Console.ReadLine();
        }
    }
}
